/**
 * 1、宏任务和微任务
 * 
 *  1、macro task:
            script 
            I/O
            setTimeout
            setInterval
            UI交互
            postMessage
            setImmediate(node环境)
    2、micro task
            promise.then
            Object.observe
            MutationObserver
            process.nextTick(node环境)

    3、任务队列：

    window.postMessage(message, targetOrigin, [transfer]) ：方法可以安全地实现跨源通信。
        通常，对于两个不同页面的脚本，只有当执行它们的页面位于具有相同的协议（通常为https），
        端口号（443为https的默认值），以及主机  (两个页面的模数 Document.domain设置为相同的值) 时，
        这两个脚本才能相互通信。
        window.postMessage() 方法提供了一种受控机制来规避此限制，只要正确的使用，这种方法就很安全。

        从广义上讲，一个窗口可以获得对另一个窗口的引用（比如 targetWindow = window.opener），
        然后在窗口上调用 targetWindow.postMessage() 方法分发一个  MessageEvent 消息。
        接收消息的窗口可以根据需要自由处理此事件 (en-US)。
        传递给 window.postMessage() 的参数（比如 message ）将通过消息事件对象暴露给接收消息的窗口。
      
      语法：otherWindow.postMessage(message, targetOrigin, [transfer]);
 */


// 1、window.postMessage()    

// The dispatched event
// 执行如下代码, 其他window可以监听分发的message:
window.addEventListener("message", receiveMessage, false);

function receiveMessage(event) {
    // For Chrome, the origin property is in the event.originalEvent
    // object.
    // 这里不准确，chrome没有这个属性
    // var origin = event.origin || event.originalEvent.origin;
    var origin = event.origin
    if (origin !== "http://example.org:8080")
        return;

    // ...
}

/**
 * 2、setImmediate(func,[param1,param2,...])
 * 该方法用来把一些需要长时间运行的操作放在一个回调函数里,在浏览器完成后面的其他语句后,就立刻执行这个回调函数.
    immediateID 是这次setImmediate方法设置的唯一ID,可以作为 window.clearImmediate 的参数.
    func 是将要执行的回调函数
    window.clearImmediate 方法可以用来取消通过setImmediate设置的将要执行的语句, 就像
 */
var immediateID = setImmediate(func, [param1, param2, ...]);
var immediateID = setImmediate(func);

/**
 * 3、Object.observe(obj, callback[, acceptList]) :该方法已被废弃
 *    Object.observe() 用来实时监测js中对象的变化，变化时调用一个方法。
 *    使用此方法，可以代替angular中的脏检查，可以大大的提高性能，详情可以看下文。
 * 参数：
        obj：被监控的对象.
        callback：当对象被修改时触发的回调函数，其参数为: 
            changes
                 一个数组，其中包含的每一个对象代表一个修改行为。每个修改行为的对象包含: 
                （1）name: 被修改的属性名称。
                （2）object: 修改后该对象的值。
                （3）type: 表示对该对象做了何种类型的修改，可能的值为"add", "update", or "delete"。
                （4）oldValue: 对象修改前的值。该值只在"update"与"delete"有效。
        acceptList：在给定对象上给定回调中要监视的变化类型列表。
            如果省略,["add", "update", "delete", "reconfigure", "setPrototype", "preventExtensions"] 将会被使用。
 */

/**
 * 4、MutationObserver接口提供了监视对DOM树所做更改的能力。
 *     它被设计为旧的Mutation Events功能的替代品，该功能是DOM3 Events规范的一部分。
 *  构造函数 MutationObserver()
 *     创建并返回一个新的 MutationObserver 它会在指定的DOM发生变化时被调用。
 *  方法
        （1）disconnect()
           阻止 MutationObserver 实例继续接收的通知，直到再次调用其observe()方法，该观察者对象包含的回调函数都不会再被调用。
        （2）observe()
            配置MutationObserver在DOM更改匹配给定选项时，通过其回调函数开始接收通知。
        （3）takeRecords()
            从MutationObserver的通知队列中删除所有待处理的通知，并将它们返回到MutationRecord对象的新Array中。
 */

// 选择需要观察变动的节点
const targetNode = document.getElementById('some-id');

// 观察器的配置（需要观察什么变动）
const config = { attributes: true, childList: true, subtree: true };

// 当观察到变动时执行的回调函数
const callback = function (mutationsList, observer) {
    // Use traditional 'for loops' for IE 11
    for (let mutation of mutationsList) {
        if (mutation.type === 'childList') {
            console.log('A child node has been added or removed.');
        }
        else if (mutation.type === 'attributes') {
            console.log('The ' + mutation.attributeName + ' attribute was modified.');
        }
    }
};

// 创建一个观察器实例并传入回调函数
const observer = new MutationObserver(callback);

// 以上述配置开始观察目标节点
observer.observe(targetNode, config);

// 之后，可停止观察
observer.disconnect();